package symbolTable.seniorST;

import org.w3c.dom.Node;
import stackAndQueue.Stack;

public class BSTNonRec<Key extends Comparable<Key>, Value> {
    private Node root;

    private class Node {
        private Key key;
        private Value val;
        private Node left, right;
        private int N;

        public Node(Key key, Value val, int N) {
            this.key = key;
            this.val = val;
            this.N = N;
        }
    }

    public int size() {
        return size(root);
    }

    private int size(Node x) {
        if (x == null)
            return 0;
        else
            return x.N;
    }

    public Value get(Key key) {
        Node x = root;
        int cmp;
        while (x != null) {
            cmp = key.compareTo(x.key);
            if (cmp < 0)
                x = x.left;
            else if (cmp > 0)
                x = x.right;
            else
                return x.val;
        }
        return null;
    }

    public void put(Key key, Value val) {
        if (root == null){
            root = new Node(key, val, 1);
            return;
        }
        Node x = root;
        int cmp;
        Stack<Node> stack = new Stack<>();

        while (true) {
            stack.push(x);
            cmp = key.compareTo(x.key);
            if (cmp < 0)
                if (x.left == null){
                    x.left = new Node(key, val, 1);
                    break;
                }
                else
                    x = x.left;
            else if (cmp > 0)
                if (x.right == null){
                    x.right = new Node(key, val, 1);
                    break;
                }
                else
                    x = x.right;
            else {
                x.val = val;
                return;
            }
        }
        for (Node s : stack) {
            s.N = size(s.left) + size(s.right) + 1;
        }
    }

    public Key min() {
        Node x = root;
        if (x == null)
            return null;
        while (x.left != null) {
            x = x.left;
        }
        return x.key;
    }

    public Key max() {
        Node x = root;
        if (x == null)
            return null;
        while (x.right != null) {
            x = x.right;
        }
        return x.key;
    }

    public Key floor(Key key) {
        Node x = root;
        Key t = null;
        int cmp;
        while (x != null) {
            cmp = key.compareTo(x.key);
            if (cmp < 0)
                x = x.left;
            else if (cmp == 0)
                return x.key;
            else {
                t = x.key;
                x = x.right;
            }
        }
        return t;
    }

    public Key ceiling(Key key) {
        Node x = root;
        Key t = null;
        int cmp;
        while (x != null) {
            cmp = key.compareTo(x.key);
            if (cmp > 0)
                x = x.right;
            else if (cmp == 0)
                return x.key;
            else {
                t = x.key;
                x = x.left;
            }
        }
        return t;
    }

    public int rank(Key key) {
        Node x = root;
        int num = 0;
        int cmp;
        while (x != null) {
            cmp = key.compareTo(x.key);
            if (cmp < 0)
                x = x.left;
            else if (cmp == 0) {
                num += size(x.left);
                break;
            } else {
                num = num + size(x.left) + 1;
                x = x.right;
            }
        }
        return num;
    }

    public Key select(int k) {
        Node x = root;
        int num = k;
        while (x != null) {
            if (size(x.left) > num)
                x = x.left;
            else if (size(x.left) == num)
                return x.key;
            else {
                num = num - size(x.left) - 1;
                x = x.right;
            }
        }
        return null;
    }

}
